/**
 * Utils类存放和业务无关的公共方法
 * @description
 */
class Utils {
    /**
     * 字符串非空验证  为空显示true
     * @param value
     * @returns {boolean}
     */
    static isEmpty(value) {
        return value == null || (typeof value === "string" && value.length === 0);
    }

    /**
     * 字符串非空验证  为空显示false
     * @param value
     * @returns {boolean}
     */
    static isNotEmpty(value) {
        return !this.isEmpty(value);
    }

    /**
     * 格式“是”or“否”
     * @param value
     * @returns {string|string}
     */
    static formatYesOrNo(value) {
        return value === 1 ? "是" : value === "0" ? "否" : null;
    }

    /**
     * 日期对象转为日期字符串
     * @param date 需要格式化的日期对象
     * @param sFormat 输出格式,默认为yyyy-MM-dd                        年：y，月：M，日：d，时：h，分：m，秒：s
     * @example  dateFormat(new Date())                               "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd')                  "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd HH:mm:ss')         "2017-02-28 13:24:00"   ps:HH:24小时制
     * @example  dateFormat(new Date(),'yyyy-MM-dd hh:mm:ss')         "2017-02-28 01:24:00"   ps:hh:12小时制
     * @example  dateFormat(new Date(),'hh:mm')                       "09:24"
     * @example  dateFormat(new Date(),'yyyy-MM-ddTHH:mm:ss+08:00')   "2017-02-28T13:24:00+08:00"
     * @example  dateFormat(new Date('2017-02-28 13:24:00'),'yyyy-MM-ddTHH:mm:ss+08:00')   "2017-02-28T13:24:00+08:00"
     * @returns {string}
     */
    static dateFormat(date, sFormat = "yyyy-MM-dd") {
        let time = {
            Year: 0,
            TYear: "0",
            Month: 0,
            TMonth: "0",
            Day: 0,
            TDay: "0",
            Hour: 0,
            THour: "0",
            hour: 0,
            Thour: "0",
            Minute: 0,
            TMinute: "0",
            Second: 0,
            TSecond: "0",
            Millisecond: 0,
        };
        time.Year = date.getFullYear();
        time.TYear = String(time.Year).substr(2);
        time.Month = date.getMonth() + 1;
        time.TMonth = time.Month < 10 ? "0" + time.Month : String(time.Month);
        time.Day = date.getDate();
        time.TDay = time.Day < 10 ? "0" + time.Day : String(time.Day);
        time.Hour = date.getHours();
        time.THour = time.Hour < 10 ? "0" + time.Hour : String(time.Hour);
        time.hour = time.Hour < 13 ? time.Hour : time.Hour - 12;
        time.Thour = time.hour < 10 ? "0" + time.hour : String(time.hour);
        time.Minute = date.getMinutes();
        time.TMinute = time.Minute < 10 ? "0" + time.Minute : String(time.Minute);
        time.Second = date.getSeconds();
        time.TSecond = time.Second < 10 ? "0" + time.Second : String(time.Second);
        time.Millisecond = date.getMilliseconds();

        return sFormat
            .replace(/yyyy/gi, String(time.Year))
            .replace(/yyy/gi, String(time.Year))
            .replace(/yy/gi, time.TYear)
            .replace(/y/gi, time.TYear)
            .replace(/MM/g, time.TMonth)
            .replace(/M/g, String(time.Month))
            .replace(/dd/gi, time.TDay)
            .replace(/d/gi, String(time.Day))
            .replace(/HH/g, time.THour)
            .replace(/H/g, String(time.Hour))
            .replace(/hh/g, time.Thour)
            .replace(/h/g, String(time.hour))
            .replace(/mm/g, time.TMinute)
            .replace(/m/g, String(time.Minute))
            .replace(/ss/gi, time.TSecond)
            .replace(/s/gi, String(time.Second))
            .replace(/fff/gi, String(time.Millisecond));
    }

    /**
     * 每次调用sequence加1
     */
    static getSequence = (function () {
        let sequence = 1;
        return function () {
            return ++sequence;
        };
    })();

    /**
     * 返回字符串长度，中文计数为2
     * @param str
     * @returns {number}
     */
    static strLength(str) {
        let len = 0;
        for (let i = 0, length = str.length; i < length; i++) {
            str.charCodeAt(i) > 255 ? (len += 2) : len++;
        }
        return len;
    }

    /**
     * 把url中的双斜杠替换为单斜杠
     * 如:http://localhost:8080//api//demo.替换后http://localhost:8080/api/demo
     * @param url
     * @returns {string}
     */
    static formatUrl(url = "") {
        let index = 0;
        if (url.startsWith("http")) {
            index = 7;
        }
        return url.substring(0, index) + url.substring(index).replace(/\/\/*/g, "/");
    }

    /**
     * 存缓存
     * @param key
     * @param value
     * @param second 有效期
     */
    static setStorage = (key, value, second) => {
        try {
            let data = {};
            if (second) {
                data = { value: value, expirse: new Date().getTime() + second * 1000 };
            } else {
                data = { value: value, expirse: 0 };
            }
            localStorage.setItem(key, JSON.stringify(data));
        } catch (error) {
            // Error saving data
        }
    };

    /**
     * 通过key获取缓存
     * @param key
     * @returns {null|any}
     */
    static getStorage = (key) => {
        try {
            const value = localStorage.getItem(key);
            if (value !== null) {
                let data = JSON.parse(value);
                if (data.expirse != null && data.expirse !== 0 && data.expirse < new Date().getTime()) {
                    localStorage.removeItem(key);
                    return null;
                } else {
                    return data.value;
                }
            }
        } catch (error) {
            // Error saving data
        }
        return null;
    };

    /**
     * 清除指定key的缓存
     * @param key
     */
    static removeStorage = (key) => {
        try {
            localStorage.removeItem(key);
        } catch (error) {
            // Error saving data
        }
    };

    /**
     * 清除缓存
     */
    static clearStorage = () => {
        try {
            localStorage.clear();
        } catch (error) {
            // Error saving data
        }
    };

    /**
     * 字符串加密
     * @returns {any}
     */
    static hex_md5 = (function () {
        //注意创建与更新需要写在一起
        const md5 = forge.md.md5.create();
        return (str) => {
            md5.update(str);
            return md5.digest().toHex();
        };
    })();

    static abc(str) {
        let a = this.hex_md5(str);
    }

    /** 产生一个随机的32位长度字符串 */
    static uuid() {
        let text = "";
        let possible = "abcdef0123456789";
        for (let i = 0; i < 19; i++) {
            text += possible.charAt(Math.floor(Math.random() * possible.length));
        }
        return text + new Date().getTime();
    }

    /**
     * 根据数字获取对应的字母
     */
    static letter(num) {
        let t = num % 26;
        if (!t) {
            t = 26;
        }
        return String.fromCodePoint(t + 64);
    }

    static getNumber(str) {
        return str.charCodeAt(0) - 64;
    }

    /**
     * {
     *    value: this.testtime, //秒数
     *    formatsp: true, //是否显示‘时’ ‘分’ ‘秒’
     *    showMinute: true //是否显示分钟
     * }
     * @param formatObj
     * @returns {*}
     */
    static formatSeconds(formatObj) {
        //{value:value,showMinute:showMinute,showHours:showHours,fromatsp:fromatsp}
        //注：value：秒数，showMinute：是否以秒分显示，showHours：是否以秒分时显示，fromatsp：true->：分割 false:以时分秒分割
        let theTime = parseInt(formatObj.value); // 秒
        let theTime1 = 0; // 分
        let theTime2 = 0; // 小时
        if (theTime > 60 && formatObj.showMinute) {
            theTime1 = parseInt(theTime / 60 + "");
            theTime = parseInt((theTime % 60) + "");
            if (theTime1 > 60 && formatObj.showHours && formatObj.showMinute) {
                theTime2 = parseInt(theTime1 / 60 + "");
                theTime1 = parseInt((theTime1 % 60) + "");
            }
        }
        let result;
        if (theTime < 10 && (theTime >= 0 || theTime1 > 0)) {
            result = "0" + theTime + (formatObj.formatsp ? "" : "秒");
        } else {
            result = "" + theTime + (formatObj.formatsp ? "" : "秒");
        }

        if (theTime1 < 10) {
            result = "0" + theTime1 + (formatObj.formatsp ? ":" : "分") + result;
        } else {
            result = "" + theTime1 + (formatObj.formatsp ? ":" : "分") + result;
        }

        if (theTime2 > 0) {
            if (theTime2 < 10) {
                result = "0" + theTime2 + (formatObj.formatsp ? ":" : "小时") + result;
            } else {
                result = "" + theTime2 + (formatObj.formatsp ? ":" : "小时") + result;
            }
        }
        return result;
    }

    /**
     * 获取两个经纬度之间的距离
     * @param lat1 第一点的纬度
     * @param lng1 第一点的经度
     * @param lat2 第二点的纬度
     * @param lng2 第二点的经度
     * @returns {Number}
     */
    static getDistance(lat1, lng1, lat2, lng2) {
        lat1 = parseFloat(lat1);
        lng1 = parseFloat(lng1);
        lat2 = parseFloat(lat2);
        lng2 = parseFloat(lng2);

        function getRad(d) {
            let PI = Math.PI;
            return (d * PI) / 180.0;
        }

        let f = getRad((lat1 + lat2) / 2);
        let g = getRad((lat1 - lat2) / 2);
        let l = getRad((lng1 - lng2) / 2);
        let sg = Math.sin(g);
        let sl = Math.sin(l);
        let sf = Math.sin(f);
        let s, c, w, r, d, h1, h2;
        let a = 6378137.0; //The Radius of eath in meter.
        let fl = 1 / 298.257;
        sg = sg * sg;
        sl = sl * sl;
        sf = sf * sf;
        s = sg * (1 - sl) + (1 - sf) * sl;
        c = (1 - sg) * (1 - sl) + sf * sl;
        w = Math.atan(Math.sqrt(s / c));
        r = Math.sqrt(s * c) / w;
        d = 2 * w * a;
        h1 = (3 * r - 1) / 2 / c;
        h2 = (3 * r + 1) / 2 / s;
        s = d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg));
        //s = s/1000;
        s = s.toFixed(2); //指定小数点后的位数。
        return s;
    }

    /**
     * @param arr 参数数组
     */
    static arrayDeduplication(arr) {}

    /**
     * 将秒转换为 分:秒
     * s int 秒数
     */
    static s_to_hs(s) {
        //计算分钟
        //算法：将秒数除以60，然后下舍入，既得到分钟数
        let h;
        h = Math.floor(s / 60);
        //计算秒
        //算法：取得秒%60的余数，既得到秒数
        s = s % 60;
        s = s.toFixed(0);
        //将变量转换为字符串
        h += "";
        s += "";
        //如果只有一位数，前面增加一个0
        h = h.length === 1 ? "0" + h : h;
        s = s.length === 1 ? "0" + s : s;
        return h + ":" + s;
    }

    /**
     * 返回当前浏览器
     * @returns {string}
     */
    static getBrowser() {
        /**
         * @class kity.Browser
         * @catalog core
         * @static
         * @description 提供浏览器信息
         */
        let browser = (function () {
            let agent = navigator.userAgent.toLowerCase(),
                opera = window.opera,
                browser;
            // 浏览器对象
            browser = {
                /**
                 * @property platform
                 * @description 获取浏览器所在系统,"Win"->Windows;"Mac"->Mac;"Lux"->Linux
                 * @type {String}
                 */
                platform: (function (navigator) {
                    let _p = {
                        win32: "Windows",
                        macintel: "Mac",
                    };
                    return _p[navigator.platform.toLowerCase()] || "Linux";
                })(navigator),
                /**
                 * 猎豹,区分两种不同内核
                 */
                lb: (function (agent) {
                    if (~agent.indexOf("lbbrowser")) {
                        return ~agent.indexOf("msie") ? "ie" : "chrome";
                    }
                    return false;
                })(agent),
                /**
                 * 搜狗
                 */
                sg: /se[\s\S]+metasr/.test(agent),
                /**
                 * 百度
                 */
                bd: !!~agent.indexOf("bidubrowser"),
                /**
                 * edge浏览器
                 */
                edge: !!~agent.indexOf("edge"),
                /**
                 * chrome初始化为false
                 * @type {Boolean}
                 */
                chrome: false,
                /**
                 * @property opera
                 * @for kity.Browser
                 * @description 判断是否为 Opera 浏览器
                 * @type {boolean}
                 */
                opera: !!opera && opera.version,
                /**
                 * @property webkit
                 * @for kity.Browser
                 * @description 判断是否为 Webkit 内核的浏览器
                 * @type {boolean}
                 */
                webkit: agent.indexOf(" applewebkit/") > -1,
                /**
                 * @property mac
                 * @for kity.Browser
                 * @description 判断是否为 Mac 下的浏览器
                 * @type {boolean}
                 */
                mac: agent.indexOf("macintosh") > -1,
            };
            /**
             * @property ie
             * @for kity.Browser
             * @description 判断是否为 IE 浏览器
             * @type {boolean}
             */
            browser.ie = !browser.lb && /(msie\s|trident.*rv:)([\w.]+)/.test(agent);
            browser.gecko = navigator.product == "Gecko" && !browser.webkit && !browser.opera && !browser.ie;
            let version = 0;
            // Internet Explorer 6.0+
            if (browser.ie) {
                version = (agent.match(/(msie\s|trident.*rv:)([\w.]+)/)[2] || 0) * 1;
                browser.ie11Compat = document.documentMode == 11;
                browser.ie9Compat = document.documentMode == 9;
            }
            // Gecko.
            if (browser.gecko) {
                let geckoRelease = agent.match(/rv:([\d\.]+)/);
                if (geckoRelease) {
                    geckoRelease = geckoRelease[1].split(".");
                    version = geckoRelease[0] * 1e4 + (geckoRelease[1] || 0) * 100 + (geckoRelease[2] || 0) * 1;
                }
            }
            // 排除其他chrome内核的浏览器的干扰
            if (
                /chrome\/(\d+\.\d)/i.test(agent) &&
                !browser.bd &&
                !browser.opera &&
                !browser.lb &&
                !browser.sg &&
                !browser.edge
            ) {
                /**
                 * @property chrome
                 * @for kity.Browser
                 * @description 判断是否为 Chrome 浏览器
                 * @type {boolean}
                 */
                browser.chrome = +RegExp["$1"];
            }
            if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
                browser.safari = +(RegExp["$1"] || RegExp["$2"]);
            }
            // Opera 9.50+
            if (browser.opera) version = parseFloat(opera.version());
            // WebKit 522+ (Safari 3+)
            if (browser.webkit) version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
            // 搜狗版本号无从得知
            // 猎豹版本号无从得知
            // 百度
            if (browser.bd) version = parseFloat(agent.match(/bidubrowser\/(\d+)/)[1]);
            // Opera 9.50+
            if (browser.opera) version = parseFloat(agent.match(/opr\/(\d+)/)[1]);
            // edge
            if (browser.edge) version = parseFloat(agent.match(/edge\/(\d+)/)[1]);
            /**
             * @property version
             * @for kity.Browser
             * @description 获取当前浏览器的版本
             * @type {Number}
             */
            browser.version = version;
            browser.isCompatible =
                !browser.mobile &&
                ((browser.ie && version >= 6) ||
                    (browser.gecko && version >= 10801) ||
                    (browser.opera && version >= 9.5) ||
                    (browser.air && version >= 1) ||
                    (browser.webkit && version >= 522) ||
                    false);
            return browser;
        })();
        // {"bd":false,"opera":false,"chrome":86,"webkit":true,"version":537,"platform":"Win","mac":false,"isCompatible":true,"edge":false,"gecko":false,"sg":false,"lb":false,"ie":false}
        if (browser.bd) {
            browser.browser = "百度";
        }
        if (browser.opera) {
            browser.browser = "Opera";
        }
        if (browser.chrome) {
            browser.browser = "Chrome";
        }
        if (browser.edge) {
            browser.browser = "edge";
        }
        if (browser.gecko) {
            browser.browser = "gecko";
        }
        if (browser.sg) {
            browser.browser = "搜狗";
        }
        if (browser.lb) {
            browser.browser = "猎豹";
        }
        if (browser.ie) {
            browser.browser = "ie";
        }
        if (browser.mac || browser.safari) {
            browser.browser = "Safari";
        }
        return browser;
    }

    /**
     * 处理菜单路径的参数
     * @param leftTreeList 左侧菜单对象的数组
     * @param type 分类 1.路由  2.链接
     */
    static processingParameters(leftTreeList, type = 2) {
        for (let i = 0; i < leftTreeList.length; i++) {
            let nowLeftMenuObj = { ...leftTreeList[i] };
            let items = nowLeftMenuObj["items"]; //是否有子节点
            if (items) {
                items = [...nowLeftMenuObj["items"]]; //创建新的对象
                for (let thisItem of items) {
                    let path = thisItem["path"];
                    if (thisItem["params"]) {
                        let params = thisItem["params"];
                        for (let thisParam in params) {
                            let paramVal = params[thisParam];
                            if (type === 2) {
                                //生成链接
                                path += "/" + paramVal;
                            } else {
                                path += "/:" + thisParam;
                            }
                        }
                        thisItem["path"] = path;
                    }
                }
                nowLeftMenuObj["items"] = items;
            } else {
                let path = nowLeftMenuObj["path"];
                if (nowLeftMenuObj["params"]) {
                    let params = nowLeftMenuObj["params"];
                    for (let thisParam in params) {
                        let paramVal = params[thisParam];
                        if (type === 2) {
                            //生成链接
                            path += "/" + paramVal;
                        } else {
                            path += "/:" + thisParam;
                        }
                    }
                    nowLeftMenuObj["path"] = path;
                }
            }
            leftTreeList[i] = nowLeftMenuObj;
        }
    }

    /**
     * 获得字符串长度（中文返回长度2   英文或数字返回长度1）
     * @param str
     * @returns {number}
     */
    static getLength(str) {
        ///<summary>获得字符串实际长度，中文2，英文1</summary>
        ///<param name="str">要获得长度的字符串</param>
        if (this.isEmpty(str)) {
            return 0;
        }
        let realLength = 0,
            len = str.length,
            charCode = -1;
        for (let i = 0; i < len; i++) {
            charCode = str.charCodeAt(i);
            if (charCode >= 0 && charCode <= 128) realLength += 1;
            else realLength += 2;
        }
        return realLength;
    }

    /**
     * js截取字符串，中英文都能用
     * s截取字符串，中英文都能用
     * 如果给定的字符串大于指定长度，截取指定长度返回，否者返回源字符串。
     * 字符串，长度
     * @param str：需要截取的字符串
     * @param len: 需要截取的长度
     */
    static cutstr(str, len) {
        let str_length = 0;
        let str_len = 0;
        let str_cut = new String();
        str_len = str.length;
        for (let i = 0; i < str_len; i++) {
            let a = str.charAt(i);
            str_length++;
            if (escape(a).length > 4) {
                //中文字符的长度经编码之后大于4
                str_length++;
            }
            str_cut = str_cut.concat(a);
            if (str_length >= len) {
                str_cut = str_cut.concat("...");
                return str_cut;
            }
        }
        //如果给定字符串小于指定长度，则返回源字符串；
        if (str_length < len) {
            return str;
        }
    }

    /**
     * 数组交集
     * @param arr1
     * @param arr2
     */
    static intersection(arr1, arr2) {
        let _arr2Set = new Set(arr2);
        return arr1.filter((item) => _arr2Set.has(item));
    }

    /**
     * 数组并集
     * @param arr1
     * @param arr2
     * @returns {any[]}
     */
    static union(arr1, arr2) {
        return Array.from(new Set([...arr1, ...arr2]));
    }

    /**
     * 补集 两个数组各自没有的集合
     * @param arr1
     * @param arr2
     */
    static complement(arr1, arr2) {
        let _arr1Set = new Set(arr1),
            _arr2Set = new Set(arr2);
        return [...arr1.filter((item) => !_arr2Set.has(item)), ...arr2.filter((item) => !_arr1Set.has(item))];
    }

    /**
     * 差集 数组arr1相对于arr2所没有的
     * @param arr1
     * @param arr2
     */
    static diff(arr1, arr2) {
        let _arr2Set = new Set(arr2);
        return arr1.filter((item) => !_arr2Set.has(item));
    }

    /**
     * 下载文件
     * @param url 服务地址
     */
    static downloadFile(url, parament) {
        let token = this.getStorage("web_token");
        url = Utils.formatUrl(url.startsWith("http") ? url : "https://app.51tcjyw.com/yjjweb" + url);
        if (parament) {
            let paramentStr = "";
            for (let thisParam in parament) {
                if (parament[thisParam]) {
                    paramentStr += "&" + thisParam + "=" + parament[thisParam];
                }
            }
            window.location.href = url + "?Authorization=" + token + paramentStr;
        } else {
            window.location.href = url + "?Authorization=" + token;
        }
    }

    static getImgUrl(path) {
        if (path) {
            return path.replace("#{ftpServicePath}", "").replace("#{webServicePath}", "");
        }
        return "";
    }

    /**
     * 创建验证码函数
     * @param x
     * @param type 0 纯数字 ,1 纯字母 , 2 数字和字母
     */
    static createCode(x, type) {
        let code = "";
        const to0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        const to1 = [
            "a",
            "b",
            "c",
            "d",
            "e",
            "f",
            "g",
            "h",
            "i",
            "j",
            "k",
            "l",
            "m",
            "n",
            "o",
            "p",
            "q",
            "r",
            "s",
            "t",
            "u",
            "v",
            "w",
            "x",
            "y",
            "z",
        ];
        const to2 = [
            0,
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            "a",
            "b",
            "c",
            "d",
            "e",
            "f",
            "g",
            "h",
            "i",
            "j",
            "k",
            "l",
            "m",
            "n",
            "o",
            "p",
            "q",
            "r",
            "s",
            "t",
            "u",
            "v",
            "w",
            "x",
            "y",
            "z",
        ];
        let codeLength = x; //验证码的长度
        let selectChar;
        if (type === 0) {
            selectChar = to0;
        } else if (type === 1) {
            selectChar = to1;
        } else if (type === 2) {
            selectChar = to2;
        } else {
            selectChar = to0;
        }

        for (let i = 0; i < codeLength; i++) {
            let charIndex = Math.floor(Math.random() * selectChar.length);
            code += selectChar[charIndex];
        }
        return code;
    }

    static delay = (timeout) => new Promise((resolve) => setTimeout(resolve, timeout));
}
